package com.yike.user.strategy.login.type;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.constant.CommonConstant;
import com.yike.common.exception.BusinessException;
import com.yike.common.redis.RedisUtil;
import com.yike.common.tool.CommonUtil;
import com.yike.common.tool.DateUtil;
import com.yike.common.tool.SHA256Util;
import com.yike.common.tool.StringUtil;
import com.yike.user.entity.User;
import com.yike.user.mapper.UserMapper;
import com.yike.user.param.LoginParam;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author Sakura
 * @date 2024/8/20 11:26
 * 账号密码登录
 */
@Component
@Log
public class AccountLoginStrategy implements LoginTypeStrategy {

    @Autowired
    private CommonUtil commonUtil;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Value("${user.password-error-num}")
    Integer PASSWORD_ERROR_NUM;

    @Override
    public User login(LoginParam loginParam) {
        // 账号密码不能为空
        if (StringUtil.isEmpty(loginParam.getUsername()) || StringUtil.isEmpty(loginParam.getPassword())) {
            throw new BusinessException(500, "账号或密码不能为空");
        }
        // 获取用户真实密码
        String password = commonUtil.getDecryptStr(loginParam.getPassword(), loginParam.getSaltKey(), true);

        // 获取当前登录用户信息，这里支持账号和手机号登录
        User user = userMapper.selectOne(Wrappers.<User>lambdaQuery()
                .nested(wrapper ->
                        wrapper.eq(User::getUsername, loginParam.getUsername())
                                .or()
                                .eq(User::getMobile, loginParam.getUsername()))
                .ne(User::getStatus, 0));
        if (ObjectUtil.isNull(user)) {
            throw new BusinessException(500, "用户名或密码错误");
        }
        // 验证密码是否正确
        if (!user.getPassword().equals(SHA256Util.getSHA256Str(password + user.getSalt()))) {
            // 用户每天输错密码不得超过最大限制数
            long errorNum = redisUtil.incr(CommonConstant.PASSWORD_ERROR_NUM + user.getId(), 1);
            if (errorNum > PASSWORD_ERROR_NUM) {
                // 密码多次错误冻结用户账号，保护账号安全，可次日自动解冻也可由管理员手动解冻
                throw new BusinessException(500, "密码输入错误次数过多账号已冻结，请重置密码或次日自行解冻");
            }
            // 设置当前计数器有效期,当前日期到晚上23：59:59
            redisUtil.expire(CommonConstant.PASSWORD_ERROR_NUM + user.getId(), DateUtil.timeToMidnight());

            throw new BusinessException(500, "用户名或密码错误"); // 此处写法固定，防止有人用脚本尝试账号
        }

        return user;
    }
}
